package com.suray.rgv.roller.core;

import com.suray.basic.wcs.utils.LoggerType;
import com.suray.basic.wcs.utils.ModuleType;
import com.suray.basic.wcs.utils.WcsFuncUtil;
import com.suray.commin.core.utils.StringUtils;
import com.suray.commin.core.utils.UUID;
import com.suray.commin.exception.Rgv60TaskException;
import com.suray.rgv.util.RgvLogger;
import com.suray.rgv60.core.Rgv60Core;
import com.suray.type.Rgv60PalletStatus;
import com.suray.type.Rgv60TaskStatus;
import com.suray.type.RollerDirectionType;
import com.suray.wcs.res.enums.Order;
import suray.rgv.communication.data.RouteInfo;
import suray.rgv.communication.util.RgvOperation;

import java.io.IOException;

/**
 * 滚筒车核心
 */
public class RgvRollerCore extends Rgv60Core {
    //小车基本信息
    private RgvRollerInfo rgvRollerInfo;

    public RgvRollerCore(int rgvNo, String serialNum) {
        super(rgvNo, serialNum, ModuleType.RGV_RES60);
        this.serialNum = serialNum;

        rgvRollerInfo = new RgvRollerInfo(serialNum, getRgv60Info());
    }

    private boolean waiteSingleTaskEnd(String des, RgvOperation operation) throws IOException {
        checkRgvStatus();
        int tick = 300;
        while (true) {
            rgvRollerInfo.analyzeRobotIO();
            if (rgvRollerInfo.getTaskStatus() == Rgv60TaskStatus.COMPLETED) {
                if (operation == null || (operation == RgvOperation.RollerLoad
                        && getPalletStatus() == Rgv60PalletStatus.CAN_GET && rgvRollerInfo.isRollerStop)
                        || (operation == RgvOperation.RollerUnLoad
                        && rgvRollerInfo.palletStatus == Rgv60PalletStatus.CAN_PUT && rgvRollerInfo.isRollerStop)) {
                    break;
                }
            }

            rgvInterrupt(des);
            if (tick > 0) {
                tick--;
            } else {
                return false;
            }
            WcsFuncUtil.delay(200);
        }

        return true;
    }

    private boolean singleTask(String targetNode, RgvOperation operation, String direction, String des,
                               boolean isScript)
            throws IOException {
        sendSingleTask(targetNode, operation, direction, isScript);
        return waiteSingleTaskEnd(des, operation);
    }

    private void sendSingleTask(String targetNode, RgvOperation operation, String direction,
                                boolean isScript) throws IOException {
        RouteInfo routeInfo = new RouteInfo();
        String taskId = UUID.randomUUID().toString();
        routeInfo.setTask_id(taskId);
        if (StringUtils.isNotEmpty(targetNode)) {
            routeInfo.setId(targetNode);
        }
        if (isScript) {
            routeInfo.setOperation("Script");
            RouteInfo.ScriptDTO scriptDTO = new RouteInfo.ScriptDTO();
            scriptDTO.setDirection(direction);
            if (operation != null) {
                scriptDTO.setOperation(operation.getStrValue());
            }
            routeInfo.setScript_args(scriptDTO);
            routeInfo.setScript_name("userpy/SingleRoller.py");
        } else {
            if (operation != null) {
                routeInfo.setOperation(operation.getStrValue());
            }
            if (StringUtils.isNotEmpty(direction)) {
                routeInfo.setDirection(direction);
            }
        }
        seerComm.sendRoute(routeInfo);
    }

    public boolean action(Order rgvActionType, Object param) throws IOException {
        checkAuthor();

        switch (rgvActionType) {
            case MANUAL_CALIBRATION:
                RgvLogger.info(LoggerType.ACTION, rgvActionType.getOrderByte(), rgvRollerInfo.serialNum, "手动校准",
                        this.getClass());
                mapManage.confirmRobotPosition();
                break;
            case CHANGE_LOCATION:
                RgvLogger.info(LoggerType.ACTION, rgvActionType.getOrderByte(), rgvRollerInfo.serialNum, "修改位置",
                        this.getClass());
                if (!changeLocation((String) param)) {
                    return false;
                }
                break;
            case CHANGE_MAP:
                RgvLogger.info(LoggerType.ACTION, rgvActionType.getOrderByte(), rgvRollerInfo.serialNum, "切换地图",
                        this.getClass());
                if (!changeMap((Integer) param)) {
                    return false;
                }
                break;
            case INITIALIZE:
                RgvLogger.info(LoggerType.ACTION, rgvActionType.getOrderByte(), rgvRollerInfo.serialNum, "初始化",
                        this.getClass());
                initParam(false);
//                seerComm.initNet((String) param);

//                int tick = 0;
//                while (!isOnLine()) {
//                    WcsFuncUtil.delay(100);
//
//                    if (tick < 30) {
//                        tick++;
//                    } else {
//                        throw new RuntimeException("初始化网络失败");
//                    }
//                }
                break;
            case PALLET_DOWN:
                RgvLogger.info(LoggerType.ACTION, rgvActionType.getOrderByte(), rgvRollerInfo.serialNum, "托盘下降",
                        this.getClass());
                RollerDirectionType unLoad = getRollerActionParam(param);
                if (!singleTask(null, RgvOperation.RollerUnLoad, unLoad.getStrValue(), "滚筒放货",
                        true)) {
                    throw new Rgv60TaskException(serialNum + " 滚筒放货失败");
                }
                RgvLogger.info(LoggerType.ACTION, rgvActionType.getOrderByte(), rgvRollerInfo.serialNum, "托盘下降成功",
                        this.getClass());
                break;
            case PALLET_UP:
                RgvLogger.info(LoggerType.ACTION, rgvActionType.getOrderByte(), rgvRollerInfo.serialNum, "托盘上升",
                        this.getClass());
                RollerDirectionType load = getRollerActionParam(param);
                sendSingleTask(null, RgvOperation.RollerLoad, load.getStrValue(), true);
                break;
            case WAIT_HAS_CARGO:
                if (!waiteSingleTaskEnd("滚筒取货", RgvOperation.RollerLoad)) {
                    throw new Rgv60TaskException(serialNum + " 滚筒取货失败");
                }
                RgvLogger.info(LoggerType.ACTION, rgvActionType.getOrderByte(), rgvRollerInfo.serialNum, "滚筒取货成功",
                        this.getClass());
                break;
            case WAIT_NO_CARGO:
                if (!waiteSingleTaskEnd("滚筒放货", RgvOperation.RollerUnLoad)) {
                    throw new Rgv60TaskException(serialNum + " 滚筒放货失败");
                }
                RgvLogger.info(LoggerType.ACTION, rgvActionType.getOrderByte(), rgvRollerInfo.serialNum, "滚筒放货成功",
                        this.getClass());
                break;
            case ROLLER_STOP:
                RgvLogger.info(LoggerType.ACTION, rgvActionType.getOrderByte(), rgvRollerInfo.serialNum, "停止滚动",
                        this.getClass());
                RollerDirectionType stop = getRollerActionParam(param);
                sendSingleTask(null, RgvOperation.RollerStop, stop.getStrValue(), true);
                break;
            default:
                RgvLogger.info(LoggerType.WARN, null, serialNum,
                        "目前不支持该指令:" + rgvActionType, this.getClass());
                break;
        }

        return true;
    }

    private RollerDirectionType getRollerActionParam(Object param) {
        if (!(param instanceof Integer)) {
            throw new Rgv60TaskException("滚筒放货指令参数错误:" + param);
        }
        RollerDirectionType rollerDirectionType = RollerDirectionType.parseType((Integer) param);
        if (rollerDirectionType == RollerDirectionType.INVALID) {
            throw new Rgv60TaskException("滚筒放货指令参数错误:" + param);
        }

        return rollerDirectionType;
    }

    public Rgv60PalletStatus getPalletStatus() {
        return rgvRollerInfo.palletStatus;
    }

}
